#include <iostream>
#include <cstdio>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


using namespace std;

void countDown(int cnt)
{
    while (cnt >= 0)
    {
        printf("cnt: %2d\r", cnt--);
        fflush(stdout);
        sleep(1);
    }
}


//sa_mask: 正在处理某个信号时 添加对其他信号的屏蔽
// void handler(int signo)
// {
//     printf("捕获到 %d 号信号, 正在处理中\n", signo);
//     countDown(10);
// }

// int main()
// {
//     struct sigaction act, oldact;
//     act.sa_handler = handler;
//     act.sa_flags = 0;
//     sigemptyset(&(act.sa_mask));
//     /*
//     正在处理信号时 当前信号会添加到block表中 因此发送同类型信号不会被处理
//     即使在此期间发送了多次同类型信号 pending表也只能记录一次
//     最初的信号处理完毕后 block表由1置0 如果pending表为1 则再次递达该信号
//     sa_mask 信号处理过程中 除了屏蔽同类型信号 还想屏蔽的信号可以添加至该信号集 
//     */
//     sigaddset(&(act.sa_mask), 3);
//     sigaction(2, &act, &oldact);
//     while (true)
//     {
//         sleep(1);
//     }
//     return 0;
// }

//利用信号进行进程等待
void handler(int signo)
{
    //父进程等待回收子进程
    printf("进程 %d 正在回收子进程\n", getpid());
    /*
    -1表示等待任意子进程
    使用循环防止多个子进程同时退出时 重复收到SIGCHLD信号 导致一些进程不能被回收
    WNOHANG不会阻塞等待回收子进程 没有子进程退出时会继续向后执行
    */
    while (waitpid(-1, nullptr, WNOHANG) > 0);
}

int main()
{
    signal(SIGCHLD, handler);
    //signal(SIGCHLD, SIG_IGN);//子进程不再需要父进程回收 而是通过os直接回收
    pid_t id = fork();
    if (id == 0)
    {
        printf("我是子进程%d\n", getpid());
        countDown(10);
    }
    else
    {
        while (true)
        {
            sleep(1);
        }
    }
    return 0;
}
